أطلق العنان لقوة اتحاد GraphQL مع تجميع المخططات. تعلم كيفية بناء واجهة برمجة تطبيقات GraphQL موحدة من خدمات متعددة، مما يحسن قابلية التوسع والصيانة.
اتحاد GraphQL: تجميع المخططات - دليل شامل
في المشهد المتطور باستمرار لتطوير التطبيقات الحديثة، أصبحت الحاجة إلى بنيات قابلة للتطوير والصيانة أمرًا بالغ الأهمية. ظهرت الخدمات المصغرة، بفضل نمطيتها الفطرية وقابليتها للنشر المستقل، كحل شائع. ومع ذلك، يمكن أن تؤدي إدارة العديد من الخدمات المصغرة إلى تعقيدات، خاصة عندما يتعلق الأمر بكشف واجهة برمجة تطبيقات موحدة لتطبيقات العميل. وهنا يأتي دور اتحاد GraphQL، وتحديدًا تجميع المخططات.
ما هو اتحاد GraphQL؟
اتحاد GraphQL هو بنية قوية تسمح لك ببناء واجهة برمجة تطبيقات GraphQL واحدة وموحدة من عدة خدمات GraphQL أساسية (غالبًا ما تمثل خدمات مصغرة). إنه يمكّن المطورين من الاستعلام عن البيانات عبر خدمات مختلفة كما لو كانت رسمًا بيانيًا واحدًا، مما يبسط تجربة العميل ويقلل من الحاجة إلى منطق تنسيق معقد من جانب العميل.
هناك نهجان أساسيان لاتحاد GraphQL:
- تجميع المخططات (Schema Stitching): يتضمن ذلك دمج مخططات GraphQL متعددة في مخطط واحد وموحد على طبقة البوابة. وهو نهج أقدم ويعتمد على المكتبات لإدارة دمج المخططات وتفويض الاستعلامات.
- اتحاد أبولو (Apollo Federation): هذا نهج أحدث وأكثر قوة يستخدم لغة مخططات تعريفية ومخطط استعلام مخصص لإدارة عملية الاتحاد. ويوفر ميزات متقدمة مثل امتدادات الأنواع، وتوجيهات المفاتيح، والتتبع الموزع.
تركز هذه المقالة على تجميع المخططات، حيث تستكشف مفاهيمها وفوائدها وقيودها وتنفيذها العملي.
فهم تجميع المخططات
تجميع المخططات هو عملية دمج مخططات GraphQL متعددة في مخطط واحد ومتماسك. يعمل هذا المخطط الموحد كواجهة، يخفي تعقيد الخدمات الأساسية عن العميل. عندما يقدم العميل طلبًا إلى المخطط المجمع، تقوم البوابة بتوجيه الطلب بذكاء إلى الخدمة (الخدمات) الأساسية المناسبة، وتسترد البيانات، وتجمع النتائج قبل إعادتها إلى العميل.
فكر في الأمر على هذا النحو: لديك العديد من المطاعم (الخدمات) كل منها متخصص في مطابخ مختلفة. تجميع المخططات يشبه قائمة طعام عالمية تجمع كل الأطباق من كل مطعم. عندما يطلب العميل (العميل) من القائمة العالمية، يتم توجيه الطلب بذكاء إلى مطابخ المطاعم المناسبة، ويتم إعداد الطعام، ثم يتم تجميعه في توصيل واحد للعميل.
المفاهيم الأساسية في تجميع المخططات
- المخططات البعيدة (Remote Schemas): هي مخططات GraphQL الفردية لكل خدمة أساسية. تعرض كل خدمة مخططها الخاص، الذي يحدد البيانات والعمليات التي توفرها.
- البوابة (Gateway): البوابة هي المكون المركزي المسؤول عن تجميع المخططات البعيدة معًا وكشف المخطط الموحد للعميل. تتلقى طلبات العميل، وتوجهها إلى الخدمات المناسبة، وتجمع النتائج.
- دمج المخططات (Schema Merging): هي عملية دمج المخططات البعيدة في مخطط واحد. غالبًا ما يتضمن ذلك إعادة تسمية الأنواع والحقول لتجنب التعارضات وتحديد العلاقات بين الأنواع عبر المخططات المختلفة.
- تفويض الاستعلام (Query Delegation): عندما يقدم العميل طلبًا إلى المخطط المجمع، تحتاج البوابة إلى تفويض الطلب إلى الخدمة (الخدمات) الأساسية المناسبة لاسترداد البيانات. يتضمن ذلك ترجمة استعلام العميل إلى استعلام يمكن فهمه من قبل الخدمة البعيدة.
- تجميع النتائج (Result Aggregation): بعد أن تسترد البوابة البيانات من الخدمات الأساسية، تحتاج إلى دمج النتائج في استجابة واحدة يمكن إعادتها إلى العميل. غالبًا ما يتضمن ذلك تحويل البيانات لتتناسب مع بنية المخطط المجمع.
فوائد تجميع المخططات
يقدم تجميع المخططات العديد من الفوائد المقنعة للمؤسسات التي تتبنى بنية الخدمات المصغرة:
- واجهة برمجة تطبيقات موحدة: توفر واجهة برمجة تطبيقات واحدة ومتسقة للعملاء، مما يبسط الوصول إلى البيانات ويقلل من حاجة العملاء إلى التفاعل مع خدمات متعددة مباشرة. وهذا يؤدي إلى تجربة مطور أنظف وأكثر سهولة.
- تقليل تعقيد العميل: يحتاج العملاء فقط إلى التفاعل مع المخطط الموحد، مما يحميهم من تعقيدات بنية الخدمات المصغرة الأساسية. وهذا يبسط التطوير من جانب العميل ويقلل من كمية الكود المطلوبة على العميل.
- زيادة قابلية التوسع: يسمح لك بتوسيع نطاق الخدمات الفردية بشكل مستقل بناءً على احتياجاتها الخاصة. وهذا يحسن قابلية التوسع والمرونة العامة للنظام. على سبيل المثال، يمكن توسيع نطاق خدمة المستخدم التي تواجه حملاً عاليًا دون التأثير على الخدمات الأخرى مثل كتالوج المنتجات.
- تحسين قابلية الصيانة: يعزز النمطية وفصل الاهتمامات، مما يسهل صيانة وتطوير الخدمات الفردية. من غير المرجح أن تؤثر التغييرات على خدمة واحدة على الخدمات الأخرى.
- التبني التدريجي: يمكن تنفيذه بشكل تدريجي، مما يسمح لك بالانتقال تدريجيًا من بنية متجانسة إلى بنية خدمات مصغرة. يمكنك البدء بتجميع واجهات برمجة التطبيقات الحالية ثم تفكيك المتجانسة تدريجيًا إلى خدمات أصغر.
قيود تجميع المخططات
بينما يقدم تجميع المخططات العديد من المزايا، من المهم أن تكون على دراية بقيوده:
- التعقيد: يمكن أن يكون تنفيذ وإدارة تجميع المخططات معقدًا، خاصة في الأنظمة الكبيرة والمعقدة. التخطيط والتصميم الدقيقان ضروريان.
- الحمل الزائد على الأداء: تقدم البوابة بعض الحمل الزائد على الأداء بسبب طبقة التوجيه الإضافية والحاجة إلى تفويض الاستعلامات وتجميع النتائج. التحسين الدقيق أمر حاسم لتقليل هذا الحمل الزائد.
- تعارض المخططات: يمكن أن تنشأ تعارضات عند دمج المخططات من خدمات مختلفة، خاصة إذا كانت تستخدم نفس أسماء الأنواع أو أسماء الحقول. يتطلب هذا تصميمًا دقيقًا للمخططات وربما إعادة تسمية الأنواع والحقول.
- ميزات متقدمة محدودة: مقارنةً باتحاد أبولو، يفتقر تجميع المخططات إلى بعض الميزات المتقدمة مثل امتدادات الأنواع وتوجيهات المفاتيح، مما قد يجعل إدارة العلاقات بين الأنواع عبر المخططات المختلفة أكثر صعوبة.
- نضج الأدوات: الأدوات والنظام البيئي المحيط بتجميع المخططات ليست ناضجة مثل تلك المحيطة باتحاد أبولو. هذا يمكن أن يجعل تصحيح الأخطاء واستكشاف المشكلات أكثر صعوبة.
التنفيذ العملي لتجميع المخططات
دعنا نمر بمثال مبسط لكيفية تنفيذ تجميع المخططات باستخدام Node.js ومكتبة graphql-tools
(وهي خيار شائع لتجميع المخططات). يتضمن هذا المثال خدمتين مصغرتين: خدمة المستخدم وخدمة المنتج.
1. تعريف المخططات البعيدة
أولاً، قم بتعريف مخططات GraphQL لكل من الخدمات البعيدة.
خدمة المستخدم (user-service.js
):
const { buildSchema } = require('graphql');
const userSchema = buildSchema(`
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
`);
const users = [
{ id: '1', name: 'Alice Smith', email: 'alice@example.com' },
{ id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];
const userRoot = {
user: (args) => users.find(user => user.id === args.id),
};
module.exports = {
schema: userSchema,
rootValue: userRoot,
};
خدمة المنتج (product-service.js
):
const { buildSchema } = require('graphql');
const productSchema = buildSchema(`
type Product {
id: ID!
name: String
price: Float
userId: ID! # مفتاح خارجي لخدمة المستخدم
}
type Query {
product(id: ID!): Product
}
`);
const products = [
{ id: '101', name: 'Laptop', price: 1200, userId: '1' },
{ id: '102', name: 'Smartphone', price: 800, userId: '2' },
];
const productRoot = {
product: (args) => products.find(product => product.id === args.id),
};
module.exports = {
schema: productSchema,
rootValue: productRoot,
};
2. إنشاء خدمة البوابة
الآن، قم بإنشاء خدمة البوابة التي ستجمع المخططين معًا.
خدمة البوابة (gateway.js
):
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');
async function createRemoteSchema(uri) {
const fetcher = async (params) => {
const response = await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
return response.json();
};
const schema = await introspectSchema(fetcher);
return makeRemoteExecutableSchema({
schema,
fetcher,
});
}
async function main() {
const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
const productSchema = await createRemoteSchema('http://localhost:4002/graphql');
const stitchedSchema = stitchSchemas({
subschemas: [
{ schema: userSchema },
{ schema: productSchema },
],
typeDefs: `
extend type Product {
user: User
}
`,
resolvers: {
Product: {
user: {
selectionSet: `{ userId }`,
resolve(product, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: userSchema,
operation: 'query',
fieldName: 'user',
args: {
id: product.userId,
},
context,
info,
});
},
},
},
},
});
const app = express();
app.use('/graphql', graphqlHTTP({
schema: stitchedSchema,
graphiql: true,
}));
app.listen(4000, () => console.log('خادم البوابة يعمل على http://localhost:4000/graphql'));
}
main().catch(console.error);
3. تشغيل الخدمات
ستحتاج إلى تشغيل خدمة المستخدم وخدمة المنتج على منافذ مختلفة. على سبيل المثال:
خدمة المستخدم (منفذ 4001):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4001, () => console.log('خدمة المستخدم تعمل على http://localhost:4001/graphql'));
خدمة المنتج (منفذ 4002):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4002, () => console.log('خدمة المنتج تعمل على http://localhost:4002/graphql'));
4. الاستعلام عن المخطط المجمع
الآن يمكنك الاستعلام عن المخطط المجمع من خلال البوابة (التي تعمل على المنفذ 4000). يمكنك تشغيل استعلام مثل هذا:
query {
product(id: "101") {
id
name
price
user {
id
name
email
}
}
}
يسترد هذا الاستعلام المنتج بالمعرف "101" ويجلب أيضًا المستخدم المرتبط به من خدمة المستخدم، مما يوضح كيف يسمح لك تجميع المخططات بالاستعلام عن البيانات عبر خدمات متعددة في طلب واحد.
تقنيات تجميع المخططات المتقدمة
إلى جانب المثال الأساسي، إليك بعض التقنيات المتقدمة التي يمكن استخدامها لتعزيز تنفيذ تجميع المخططات الخاص بك:
- تفويض المخطط: يسمح لك هذا بتفويض أجزاء من الاستعلام إلى خدمات مختلفة بناءً على البيانات المطلوبة. على سبيل المثال، قد تقوم بتفويض حل نوع `User` إلى خدمة المستخدم وحل نوع `Product` إلى خدمة المنتج.
- تحويل المخطط: يتضمن ذلك تعديل مخطط خدمة بعيدة قبل تجميعه في المخطط الموحد. يمكن أن يكون هذا مفيدًا لإعادة تسمية الأنواع والحقول، أو إضافة حقول جديدة، أو إزالة الحقول الموجودة.
- المحولات المخصصة: يمكنك تحديد محولات مخصصة في البوابة للتعامل مع تحويلات البيانات المعقدة أو لجلب البيانات من خدمات متعددة ودمجها في نتيجة واحدة.
- مشاركة السياق: غالبًا ما يكون من الضروري مشاركة معلومات السياق بين البوابة والخدمات البعيدة، مثل رموز المصادقة أو معرفات المستخدم. يمكن تحقيق ذلك عن طريق تمرير معلومات السياق كجزء من عملية تفويض الاستعلام.
- معالجة الأخطاء: قم بتنفيذ معالجة قوية للأخطاء للتعامل بأمان مع الأخطاء التي تحدث في الخدمات البعيدة. قد يتضمن ذلك تسجيل الأخطاء، أو إرجاع رسائل خطأ سهلة الاستخدام، أو إعادة محاولة الطلبات الفاشلة.
الاختيار بين تجميع المخططات واتحاد أبولو
بينما يعد تجميع المخططات خيارًا قابلاً للتطبيق لاتحاد GraphQL، فقد أصبح اتحاد أبولو الخيار الأكثر شيوعًا نظرًا لميزاته المتقدمة وتجربة المطور المحسنة. إليك مقارنة بين النهجين:
الميزة | تجميع المخططات | اتحاد أبولو |
---|---|---|
تعريف المخطط | يستخدم لغة مخطط GraphQL الحالية | يستخدم لغة مخططات تعريفية مع توجيهات |
تخطيط الاستعلام | يتطلب تفويضًا يدويًا للاستعلام | تخطيط تلقائي للاستعلام بواسطة بوابة أبولو |
امتدادات الأنواع | دعم محدود | دعم مدمج لامتدادات الأنواع |
توجيهات المفاتيح | غير مدعوم | يستخدم توجيه @key لتحديد الكيانات |
التتبع الموزع | يتطلب تنفيذًا يدويًا | دعم مدمج للتتبع الموزع |
الأدوات والنظام البيئي | أدوات أقل نضجًا | أدوات أكثر نضجًا ومجتمع كبير |
التعقيد | يمكن أن يكون معقدًا للإدارة في الأنظمة الكبيرة | مصمم للأنظمة الكبيرة والمعقدة |
متى تختار تجميع المخططات:
- لديك خدمات GraphQL حالية وترغب في دمجها بسرعة.
- تحتاج إلى حل اتحاد بسيط ولا تتطلب ميزات متقدمة.
- لديك موارد محدودة وترغب في تجنب الحمل الزائد لإعداد اتحاد أبولو.
متى تختار اتحاد أبولو:
- أنت تبني نظامًا كبيرًا ومعقدًا مع فرق وخدمات متعددة.
- تحتاج إلى ميزات متقدمة مثل امتدادات الأنواع، وتوجيهات المفاتيح، والتتبع الموزع.
- تريد حل اتحاد أكثر قوة وقابلية للتوسع.
- تفضل نهجًا أكثر تعريفية وتلقائية للاتحاد.
أمثلة واقعية وحالات استخدام
فيما يلي بعض الأمثلة الواقعية لكيفية استخدام اتحاد GraphQL، بما في ذلك تجميع المخططات:
- منصة التجارة الإلكترونية: قد تستخدم منصة التجارة الإلكترونية اتحاد GraphQL لدمج البيانات من خدمات متعددة، مثل خدمة كتالوج المنتجات، وخدمة المستخدم، وخدمة الطلبات، وخدمة الدفع. هذا يسمح للعملاء باسترداد جميع المعلومات التي يحتاجونها بسهولة لعرض تفاصيل المنتج، وملفات تعريف المستخدم، وتاريخ الطلبات، ومعلومات الدفع.
- منصة التواصل الاجتماعي: يمكن لمنصة التواصل الاجتماعي استخدام اتحاد GraphQL لدمج البيانات من الخدمات التي تدير ملفات تعريف المستخدمين، والمشاركات، والتعليقات، والإعجابات. وهذا يمكّن العملاء من جلب جميع المعلومات المطلوبة بكفاءة لعرض ملف تعريف المستخدم، ومشاركاته، والتعليقات والإعجابات المرتبطة بتلك المشاركات.
- تطبيق الخدمات المالية: قد يستخدم تطبيق الخدمات المالية اتحاد GraphQL لدمج البيانات من الخدمات التي تدير الحسابات، والمعاملات، والاستثمارات. وهذا يسمح للعملاء باسترداد جميع المعلومات التي يحتاجونها بسهولة لعرض أرصدة الحسابات، وتاريخ المعاملات، والمحافظ الاستثمارية.
- نظام إدارة المحتوى (CMS): يمكن لنظام إدارة المحتوى الاستفادة من اتحاد GraphQL لدمج البيانات من مصادر مختلفة مثل المقالات والصور ومقاطع الفيديو والمحتوى الذي ينشئه المستخدمون. وهذا يسمح بواجهة برمجة تطبيقات موحدة لجلب كل المحتوى المتعلق بموضوع أو مؤلف معين.
- تطبيق الرعاية الصحية: دمج بيانات المرضى من أنظمة مختلفة مثل السجلات الصحية الإلكترونية (EHR)، ونتائج المختبرات، وجدولة المواعيد. وهذا يوفر للأطباء نقطة وصول واحدة إلى معلومات شاملة عن المريض.
أفضل الممارسات لتجميع المخططات
لضمان تنفيذ ناجح لتجميع المخططات، اتبع أفضل الممارسات التالية:
- خطط لمخططك بعناية: قبل أن تبدأ في تجميع المخططات معًا، خطط بعناية لهيكل المخطط الموحد. يتضمن ذلك تحديد العلاقات بين الأنواع عبر المخططات المختلفة، وإعادة تسمية الأنواع والحقول لتجنب التعارضات، والنظر في أنماط الوصول إلى البيانات بشكل عام.
- استخدم اصطلاحات تسمية متسقة: اعتمد اصطلاحات تسمية متسقة للأنواع والحقول والعمليات عبر جميع الخدمات. سيساعد هذا في تجنب التعارضات وتسهيل فهم المخطط الموحد.
- وثق مخططك: وثق المخطط الموحد بشكل شامل، بما في ذلك أوصاف الأنواع والحقول والعمليات. سيجعل هذا من السهل على المطورين فهم واستخدام المخطط.
- راقب الأداء: راقب أداء البوابة والخدمات البعيدة لتحديد ومعالجة أي اختناقات في الأداء. استخدم أدوات مثل التتبع الموزع لتتبع الطلبات عبر خدمات متعددة.
- طبق الأمان: طبق تدابير أمنية مناسبة لحماية البوابة والخدمات البعيدة من الوصول غير المصرح به. قد يتضمن ذلك استخدام آليات المصادقة والترخيص، بالإضافة إلى التحقق من صحة الإدخال وترميز الإخراج.
- أصدر نسخًا من مخططك: أثناء تطوير مخططاتك، قم بإصدار نسخ منها بشكل مناسب لضمان أن يتمكن العملاء من الاستمرار في استخدام الإصدارات الأقدم من المخطط دون انقطاع. سيساعد هذا في تجنب التغييرات الكاسرة وضمان التوافق مع الإصدارات السابقة.
- أتمتة النشر: أتمتة نشر البوابة والخدمات البعيدة لضمان إمكانية نشر التغييرات بسرعة وموثوقية. سيساعد هذا في تقليل مخاطر الأخطاء وتحسين مرونة النظام بشكل عام.
الخاتمة
يقدم اتحاد GraphQL مع تجميع المخططات نهجًا قويًا لبناء واجهات برمجة تطبيقات موحدة من خدمات متعددة في بنية الخدمات المصغرة. من خلال فهم مفاهيمه الأساسية وفوائده وقيوده وتقنيات تنفيذه، يمكنك الاستفادة من تجميع المخططات لتبسيط الوصول إلى البيانات وتحسين قابلية التوسع وتعزيز قابلية الصيانة. بينما ظهر اتحاد أبولو كحل أكثر تقدمًا، يظل تجميع المخططات خيارًا قابلاً للتطبيق للسيناريوهات الأبسط أو عند دمج خدمات GraphQL الحالية. فكر بعناية في احتياجاتك ومتطلباتك المحددة لاختيار أفضل نهج لمؤسستك.